package com.sen.common.tags;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sen.common.orm.PublicDao;
import com.sen.common.utils.spring.SpringUtils;
import com.sen.common.widget.form.CheckBox;
import com.sen.common.widget.form.CheckableInput;
import com.sen.common.widget.form.Label;
import com.sen.common.widget.form.Radio;

/**
 * 不同于下拉选择, 提供的是单选/多选选择.
 * 
 * @author sen
 */
public abstract class AbstractChoiceTag extends TagSupport {
	private static final long serialVersionUID = -1533001613128782340L;

	private static Logger LOG = LoggerFactory.getLogger(AbstractChoiceTag.class);

	protected PublicDao publicDao;
	
	/**
	 * 控件的name属怀.
	 */
	private String name;
	/**
	 * 勾选的值, 可以设置多个值, 用逗号分隔. 如S01,S02,S03
	 */
	private String checkedValue;
	/**
	 * 默认勾选的值, 可以设置多个值, 用逗号分隔. 如S01,S02,S03
	 */
	private String defaultCheckedValue;
	/**
	 * 去除的选项值, 可以设置多个值, 用逗号分隔. 如S01,S02,S03
	 */
	private String excludeValues;
	/**
	 * 是否多选(checkbox)
	 */
	private String multipleChoice = "false";

	private Map<String, String> choices;

	@Override
	public int doStartTag() throws JspException {
		JspWriter out = null;
		try {
			publicDao = SpringUtils.getBean(pageContext.getServletContext(),
					"publicDao", PublicDao.class);

			choices = new LinkedHashMap<String, String>();

			out = pageContext.getOut();
			out.print(buildChoiceHtml());
			
			out.flush();
		} catch (Exception e) {
			LOG.warn("AbstractChoiceTag报错", e);
		}
		return SKIP_BODY;
	}

	private String buildChoiceHtml() {
		StringBuffer html = new StringBuffer();
		addChoices();
		if (MapUtils.isEmpty(choices)) {
			return html.toString();
		}
		for (Map.Entry<String, String> choice : choices.entrySet()) {
			html.append(buildChoiceWidget(choice.getKey(), choice.getValue()));
		}
		return html.toString();
	}

	private String buildChoiceWidget(String value, String text) {
		if (isExcludeThis(value)) {
			return StringUtils.EMPTY;
		}
		CheckableInput choiceWidget = new Radio();
		if (BooleanUtils.toBoolean(multipleChoice)) {
			choiceWidget = new CheckBox();
		}
		choiceWidget.name(name);
		String choiceId = generateChoiceId();
		choiceWidget.value(value).id(choiceId);
		if (isChecked(value)) {
			choiceWidget.checked();
		}
		return choiceWidget.toHtml() + buildLabelWidget(text, choiceId);
	}

	private boolean isExcludeThis(String value) {
		if (StringUtils.isBlank(excludeValues)) {
			return false;
		}
		String[] shouldExcludes = excludeValues.split(",");
		for (String shouldExclude : shouldExcludes) {
			if (value.equals(shouldExclude)) {
				return true;
			}
		}
		return false;
	}

	private String generateChoiceId() {
		return "__choice_tag_" + genenrateRandomNumber() + "__";
	}

	private int genenrateRandomNumber() {
		Random random = new Random();
		return random.nextInt();
	}

	private boolean isChecked(String value) {
		if (StringUtils.isEmpty(value)) {
			return false;
		}
		return isCheckedBy(value, checkedValue)
				|| isCheckedBy(value, defaultCheckedValue);
	}

	private boolean isCheckedBy(String value, String according) {
		if (StringUtils.isBlank(according)) {
			return false;
		}
		String[] shouldCheckeds = according.split(",");
		for (String shouldChecked : shouldCheckeds) {
			if (value.equals(shouldChecked)) {
				return true;
			}
		}
		return false;
	}

	private String buildLabelWidget(String text, String labelFor) {
		return new Label(text).forId(labelFor).toHtml();
	}

	// ----------- for subclasses ----------------------
	protected abstract void addChoices();

	protected void addChoice(String value, String text) {
		choices.put(value, text);
	}

	// -------------------------------------------------------
	public void setName(String name) {
		this.name = name;
	}

	public void setCheckedValue(String checkedValue) {
		this.checkedValue = checkedValue;
	}

	public void setDefaultCheckedValue(String defaultCheckedValue) {
		this.defaultCheckedValue = defaultCheckedValue;
	}

	public void setMultipleChoice(String multipleChoice) {
		this.multipleChoice = multipleChoice;
	}

	public void setExcludeValues(String excludeValues) {
		this.excludeValues = excludeValues;
	}
}
